#include "server.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <time.h>

typedef struct{
    bool connect;
    struct sockaddr_un addr;
    socklen_t len_t;
    int socket_fd;
    int fd;

    pthread_t rev_check_thread;
    pthread_t send_check_thread;
    bool exit_rev_thread;
    bool exit_send_thread;
    const uint16_t send_us;
    const uint16_t timeout_ms;
    bool should_send;
}Server_t;

static Server_t server = { \
    .connect = false, \
    .socket_fd = -1, \
    .fd = -1, \
    .exit_rev_thread = true, \
    .exit_send_thread = true, \
    .send_us = 20000, \
    .timeout_ms = 50, \
    .should_send = false \
};
 
static void Disconnect();
static int Write(uint8_t *buf, uint8_t len);
static int Read(uint8_t *buf, int len, uint16_t timeout_ms);
static void Server_Receive();

static void handle_exit(int sig)
{
    printf("\r\n");
    LOG_ERROR("Server receive signal %d",sig);
	if(sig == SIGINT)
	{
		LOG_INFO("You have press \"Ctrl+C\" to stop program!");
        exit(0);
    }
    // else if(sig == SIGPIPE)
	// {
	// 	LOG_INFO("continue communication!");
    //     Server_Connect();
	// }
}

int Server_Init()
{
    struct sigaction act;

	act.sa_handler = handle_exit;
	act.sa_flags = SA_RESETHAND;
    sigaction(SIGINT,&act,NULL);
    act.sa_handler = SIG_IGN;
    sigaction(SIGPIPE,&act,NULL);

    server.socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);  // SOCK_STREAM
    if (server.socket_fd < 0)  
    {  
        LOG_ERROR("cannot create local socket, %s", strerror(errno));
        return false;  
    }
    else
    {
        LOG_DEBUG("socket success:%d", server.socket_fd);
    }
    // 设置服务器参数  
    server.addr.sun_family = AF_UNIX;  
    strncpy(server.addr.sun_path, SOCKET_PATH, sizeof(server.addr.sun_path));  
    server.len_t = sizeof(server.addr);

    unlink(SOCKET_PATH);  // 删除该名字的本地套接字文件，可能会存在权限问题，导致无法删除

    // 绑定socket地址 
    int ret = bind(server.socket_fd, (struct sockaddr*)&server.addr, server.len_t);

    if (ret < 0)  
    {  
        LOG_ERROR("cannot bind server socket, %s", strerror(errno));
        close(server.socket_fd);  
        unlink(SOCKET_PATH);  
        return false;  
	}

	ret = listen(server.socket_fd,1);

	if (ret < 0)
    {  
        LOG_ERROR("cannot listen server socket, %s", strerror(errno));
        close(server.socket_fd);  
        unlink(SOCKET_PATH);  
        return false;  
	}

    server.exit_rev_thread = false;
    server.exit_send_thread = false;
    pthread_create(&server.rev_check_thread, NULL, (void *(*) (void *))Server_Receive, NULL);
    pthread_create(&server.send_check_thread, NULL, (void *(*) (void *))Server_Send, NULL);

    return 0;
}

int Server_Connect()
{
    LOG_INFO("01 server.socket_fd = %d", server.socket_fd);
    int fd = accept(server.socket_fd, (struct sockaddr *)&server.addr, &server.len_t);
    LOG_INFO("02 server.socket_fd = %d", server.socket_fd);
    if (fd < 0)
    {
        LOG_ERROR("accept failed: %s", strerror(errno));
    }

    server.fd = fd;
    server.connect = true;

    LOG_INFO("new connection established,server.fd = %d", server.fd);


    return 0;
}

static void Disconnect()
{
    close(server.fd);
    server.fd = -1;
    server.connect = false;

    LOG_ERROR("Server deconnect with client!");
}

static int Write(uint8_t *buf, uint8_t len)
{
    int bytes_left = len;
	int written_bytes;

	if (server.fd < 0)
	{
        Server_Connect();
		return -1;
	}

	while (bytes_left > 0) 
	{ 
		/* 开始写*/ 
		written_bytes = send(server.fd, buf, bytes_left, MSG_DONTWAIT); 

		if (written_bytes <= 0) /* 出错了*/ 
		{ 
			if (errno == EINTR) /* 中断错误 我们继续写*/ 
			{
				LOG_ERROR("errno == EINTR continue");
				continue;
			}
			else if(errno == EAGAIN) /* EAGAIN : Resource temporarily unavailable*/ 
			{
				usleep(1000 * 100);//等待100毫秒，希望发送缓冲区能得到释放
//				LOG_ERROR("errno == EAGAIN continue");
				continue;
			}
            else if(errno == EPIPE) /*断开连接后，产生这个信号*/
            {
                LOG_ERROR("errno = %d, strerror = %s" , errno, strerror(errno));
                Disconnect();
                return -1;
            }
			else /* 其他错误 没有办法,只好退了*/ 
			{
				LOG_ERROR("errno = %d, strerror = %s" , errno, strerror(errno));
				// sleep(1);
				return -1;
			}
		}
        else
        {
            bytes_left -= written_bytes; 
		    buf += written_bytes;/* 从剩下的地方继续写?? */ 
        }
		
	}
	return len;
}

static int Read(uint8_t *buf, int len, uint16_t timeout_ms)
{
	int i = 0;
	int ret;
	fd_set fds;
	struct timeval timeout;

	if (server.fd < 0)
	{
        LOG_ERROR("Read error:Server deconnect with client!");
		sleep(1);
		return -1;
	}

	// while (isReady() && i < len)
    while (i < len)
	{
		FD_ZERO(&fds);
		FD_SET(server.fd, &fds);

        timeout.tv_sec = timeout_ms / 1000;
        timeout.tv_usec = (timeout_ms % 1000) * 1000;

		ret = select(server.fd + 1, &fds, NULL, NULL, &timeout);

		if (ret < 0)
		{
			LOG_ERROR("-------select error %s------------",strerror(errno));
            Disconnect();
			return -1;
		}
		else if (ret == 0)
		{
			LOG_ERROR("select function \033[33mtimeout!\033[0m， [%d]", timeout_ms);
			return i;
		}

		if (FD_ISSET(server.fd, &fds) && i < len)
		{
			ret = recv(server.fd, buf + i, len - i, MSG_DONTWAIT);

			if (ret < 0)
			{
			    LOG_ERROR("server read %d bytes failed, %s", len - i, strerror(errno));
            }
			else 
			{
			    i += ret;
			}
		}
	}
	return i;
}

static void Server_Send_Judge()
{
    static clock_t last_clock = 0;
    double period;

    period = (double)(clock() - last_clock) / CLOCKS_PER_SEC;
    uint64_t handle_time = (uint64_t)(period * 1000000); // to us.
    if (handle_time < server.send_us)
    {
        usleep((__useconds_t)(server.send_us - handle_time));
    }	
    else
    {
        LOG_ERROR("serial handle_time %ld, period %f.", handle_time, period);
        // usleep(10000);
    }

    server.should_send = true;
    last_clock = clock();
}

void Server_Send()
{
    CPU_BINDING(1);
    SET_THREAD_SCHEDULE;

    char buf[SOCKET_BYTE_CNT] = {0};
    int64_t cur_time;
	int64_t last_time;
    cur_time = tUTCMSec();
    last_time = cur_time;
    int delta_time;
    uint8_t counter = 0;
    uint32_t info = 0;

    LOG_INFO("Enter to Server_Send");
    while (!server.exit_send_thread)
    {
		Server_Send_Judge();
        
        if (server.should_send)
        {
            if (Write(buf, SOCKET_BYTE_CNT) < 0)
            {
                continue;
            }
            // if (server.connect) DateDebug("send data", buf, SOCKET_BYTE_CNT);

            info++;
            buf[0] = 0xAA;
            buf[1] = 0x55;
            buf[2] = 0x02;
            buf[3] = info & 0xff;
            buf[4] = (info >> 8) & 0xff;
            buf[5] = (info >> 16) & 0xff;
            buf[6] = (info >> 24) & 0xff;
            buf[SOCKET_BYTE_CNT-2] = 0xCC;
            buf[SOCKET_BYTE_CNT-1] = 0x33;

        #ifdef SOCKET_SNED_OVERTIME_DEBUG
            cur_time = tUTCMSec();
            delta_time = cur_time - last_time;
            if (delta_time < 18 || delta_time > 22)
            {
                LOG_ERROR("server send overtime %d ms.", delta_time);
            }
            else
            {
                LOG_DEBUG("server send overtime %d ms.", delta_time);
            }
            last_time = cur_time;
        #endif
            

            if (server.connect) ++counter;
            if (50 == counter)
            {
                counter = 0;
                LOG_DEBUG("Server have send!");
            }
            server.should_send = false;
        }
    }
    
}

static void Server_Receive()
{
    CPU_BINDING(1);
    SET_THREAD_SCHEDULE;
    
    char buf[SOCKET_BYTE_CNT] = {0};
    int64_t cur_time;
	int64_t last_time;
    cur_time = tUTCMSec();
    last_time = cur_time;
    int delta_time;

    LOG_INFO("Enter to Server_Receive");
    while (!server.exit_rev_thread)
    {
        if (Read(buf, SOCKET_BYTE_CNT, server.timeout_ms) < 0)
            continue;
        // if (server.connect) DateDebug("receive data", buf, SOCKET_BYTE_CNT);
    
    #ifdef SOCKET_REC_OVERTIME_DEBUG
        cur_time = tUTCMSec();
        delta_time = cur_time - last_time;
        if (delta_time < 18 || delta_time > 22)
        {
            LOG_ERROR("server read overtime %d ms.", delta_time);
        }
        else
        {
            LOG_DEBUG("server read overtime %d ms.", delta_time);
        }
        last_time = cur_time;
    #endif
    }
    LOG_INFO("Exit to Server_Receive");
}
